home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / iritsm3s.zip / IRIT2NFF.C < prev    next >
C/C++ Source or Header  |  1992-02-26  |  24KB  |  773 lines

  1. /*****************************************************************************
  2. * Filter to convert IRIT data files to NFF format.                 *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 1.0, Jan 1992    *
  5. *****************************************************************************/
  6.  
  7. #ifdef __MSDOS__
  8. #include <dos.h>
  9. #include <alloc.h>
  10. #endif /* __MSDOS__ */
  11.  
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include <string.h>
  15. #include <time.h>
  16. #include "irit_sm.h"
  17. #include "iritprsr.h"
  18. #include "getarg.h"
  19. #include "genmat.h"
  20.  
  21. #define DEFAULT_KD      " 1.0"
  22. #define DEFAULT_KS      " 0.0"
  23. #define DEFAULT_SHINE   " 0.0"
  24. #define DEFAULT_TRANS   " 0.0"
  25. #define DEFAULT_INDEX   " 0.0"
  26. #define DEFAULT_COLOR    " 1.0 1.0 1.0"
  27.  
  28. #define DIST_EPSILON    2e-4
  29. #define SIZE_EPSILON    1e-5
  30. #define CONVEX_EPSILON  1e-3
  31.  
  32. #define STRCAT2(Str1, Str2, Str3) strcat(strcat(Str1, Str2), Str3)
  33.  
  34.  
  35. #ifdef __MSDOS__
  36. extern unsigned int _stklen = 32766;         /* Increase default stack size. */
  37. #endif /* __MSDOS__ */
  38.  
  39. #ifdef NO_CONCAT_STR
  40. static char *VersionStr =
  41.     "Irit2Nff        Version 3.0,    Gershon Elber,\n\
  42.      (C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
  43. #else
  44. static char *VersionStr = "Irit2Nff    " VERSION ",    Gershon Elber,    "
  45.     __DATE__ ",   " __TIME__ "\n"
  46.     "(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
  47. #endif /* NO_CONCAT_STR */
  48.  
  49. static char
  50.     *CtrlStr = "Irit2Nff l%- 4%- c%- f%-FineNess!d o%-OutName!s g%- z%- DFiles!*s";
  51. static char
  52.     *OutFileName = "Irit2Nff";
  53.  
  54. static int
  55.     GlblCPPSupport = FALSE,
  56.     GlblFineNess = 5,
  57.     GlblDumpOnlyGeometry = FALSE,
  58.     FourPerFlat = FALSE;
  59.  
  60. static MatrixType CrntViewMat;            /* This is the current view! */
  61.  
  62. static int TransColorTable[][4] = {
  63.     { /* BLACK        */ 0,    0,   0,   0 },
  64.     { /* BLUE        */ 1,    0,   0, 255 },
  65.     { /* GREEN        */ 2,    0, 255,   0 },
  66.     { /* CYAN        */ 3,    0, 255, 255 },
  67.     { /* RED        */ 4,  255,   0,   0 },
  68.     { /* MAGENTA     */ 5,  255,   0, 255 },
  69.     { /* BROWN        */ 6,   50,   0,   0 },
  70.     { /* LIGHTGRAY    */ 7,  127, 127, 127 },
  71.     { /* DARKGRAY    */ 8,   63,  63,  63 },
  72.     { /* LIGHTBLUE    */ 9,    0,   0, 255 },
  73.     { /* LIGHTGREEN    */ 10,   0, 255,   0 },
  74.     { /* LIGHTCYAN    */ 11,   0, 255, 255 },
  75.     { /* LIGHTRED    */ 12, 255,   0,   0 },
  76.     { /* LIGHTMAGENTA    */ 13, 255,   0, 255 },
  77.     { /* YELLOW        */ 14, 255, 255,   0 },
  78.     { /* WHITE        */ 15, 255, 255, 255 },
  79.     { /* BROWN        */ 20,  50,   0,   0 },
  80.     { /* DARKGRAY    */ 56,  63,  63,  63 },
  81.     { /* LIGHTBLUE    */ 57,   0,   0, 255 },
  82.     { /* LIGHTGREEN    */ 58,   0, 255,   0 },
  83.     { /* LIGHTCYAN    */ 59,   0, 255, 255 },
  84.     { /* LIGHTRED    */ 60, 255,   0,   0 },
  85.     { /* LIGHTMAGENTA    */ 61, 255,   0, 255 },
  86.     { /* YELLOW        */ 62, 255, 255,   0 },
  87.     { /* WHITE        */ 63, 255, 255, 255 },
  88.     {               -1,   0,   0,   0 }
  89. };
  90.  
  91. static IPObjectStruct *MainGetDataFiles(char **DataFileNames,
  92.                     int NumOfDataFiles);
  93. static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf, int FourPerFlat,
  94.                                 int FineNess);
  95. static void DumpDataForNFF(IPObjectStruct *PObjects);
  96. static int DumpOneObject(FILE *FRay, FILE *FGeom, IPObjectStruct *PObject);
  97. static int DumpOnePolygon(FILE *f, IPPolygonStruct *PPolygon);
  98. static int IsConvexPolygon(IPPolygonStruct *Pl);
  99. static RealType *MapPoint(RealType *Pt);
  100. static RealType *MapVector(RealType *Pt, RealType *Vec);
  101. static void MyExit(int ExitCode);
  102.  
  103. /*****************************************************************************
  104. * Main routine - Read Parameter    line and do what you need...             *
  105. *****************************************************************************/
  106. void main(int argc, char **argv)
  107. {
  108.     int Error,
  109.     FineNessFlag = FALSE,
  110.     LinearOnePolyFlag = FALSE,
  111.     VerFlag = FALSE,
  112.     OutFileFlag = FALSE,
  113.     NumFiles = 0;
  114.     char Line[LINE_LEN_LONG], *p,
  115.     **FileNames = NULL;
  116.     IPObjectStruct *PObjects;
  117.  
  118. #ifdef __MSDOS__
  119.     ctrlbrk((int (*)()) MyExit);              /* Kill process if ^C. */
  120. #endif /* __MSDOS__ */
  121.  
  122.     if ((Error = GAGetArgs (argc, argv, CtrlStr, &LinearOnePolyFlag,
  123.                 &FourPerFlat, &GlblCPPSupport,
  124.                 &FineNessFlag, &GlblFineNess,  &OutFileFlag,
  125.                 &OutFileName, &GlblDumpOnlyGeometry,
  126.                 &VerFlag, &NumFiles, &FileNames)) != 0) {
  127.     GAPrintErrMsg(Error);
  128.     GAPrintHowTo(CtrlStr);
  129.     MyExit(1);
  130.     }
  131.  
  132.     if (VerFlag) {
  133.     fprintf(stderr, "\n%s\n\n", VersionStr);
  134.     GAPrintHowTo(CtrlStr);
  135.     MyExit(0);
  136.     }
  137.  
  138.     if (LinearOnePolyFlag) {
  139.     fprintf(stderr, "Linear patch side will have a single polygon.\n");
  140.     CagdSetLinear2Poly(CAGD_ONE_POLY_PER_COLIN);
  141.     }
  142.     else
  143.         CagdSetLinear2Poly(CAGD_REG_POLY_PER_LIN);
  144.  
  145.     fprintf(stderr, "%s triangles per flat will be created.\n",
  146.         FourPerFlat ? "Four" : "Two");
  147.  
  148.     if (GlblDumpOnlyGeometry && !GlblCPPSupport) {
  149.     fprintf(stderr, "Flag -g makes sense only with -c.\n");
  150.     MyExit(1);
  151.     }
  152.     
  153.     if (!NumFiles) {
  154.     fprintf(stderr, "No data file names where given, exit.\n");
  155.     GAPrintHowTo(CtrlStr);
  156.     MyExit(1);
  157.     }
  158.  
  159.     if (!OutFileFlag) {        /* Pick the first input name as output name. */
  160.     strcpy(Line, FileNames[0]);
  161.     if ((p = strrchr(Line, '.')) != NULL);        /* Remove old file type. */
  162.         *p = 0;
  163.     OutFileName = malloc(strlen(Line) + 1);
  164.     strcpy(OutFileName, Line);
  165.     }
  166.  
  167.     /* Get the data files: */
  168.     IritPrsrPolyListCirc = FALSE;
  169.     PObjects = MainGetDataFiles(FileNames, NumFiles);
  170.  
  171.     if (IritPrsrWasPrspMat)
  172.     MultTwo4by4(CrntViewMat, IritPrsrViewMat, IritPrsrPrspMat);
  173.     else
  174.     GEN_COPY(CrntViewMat, IritPrsrViewMat, sizeof(MatrixType));
  175.  
  176.     DumpDataForNFF(PObjects);
  177.  
  178.     MyExit(0);
  179. }
  180.  
  181. /*****************************************************************************
  182. * Main routine to read the data    description files:                 *
  183. * Returns pointer to pointers on FileDescription structures (one per file).  *
  184. *****************************************************************************/
  185. static IPObjectStruct *MainGetDataFiles(char **DataFileNames,
  186.                     int NumOfDataFiles)
  187. {
  188.     int    i;
  189.     FILE *f;
  190.     char
  191.     *ErrorMsg = NULL;
  192.     IPObjectStruct *PObj, *PObjTail,
  193.     *PObjHead = NULL;
  194.  
  195.     for    (i = 0; i < NumOfDataFiles; i++) {
  196. #ifdef __MSDOS__
  197.     if ((f = fopen(*DataFileNames, "rt")) == NULL) {   /* Open the file. */
  198. #else
  199.     if ((f = fopen(*DataFileNames, "r")) == NULL) {    /* Open the file. */
  200. #endif /* __MSDOS__ */
  201.         fprintf(stderr, "Can't open data file %s\n", *DataFileNames);
  202.         MyExit(1);
  203.     }
  204.  
  205.     if ((PObj = IritPrsrGetObjects(f)) != NULL) {  /* Get the data file. */
  206.         PObjTail = PObj;
  207.         while (PObjTail -> Pnext) PObjTail = PObjTail -> Pnext;
  208.         PObjTail -> Pnext = PObjHead;
  209.         PObjHead = PObj;
  210.     }
  211.  
  212.     fclose(f);                      /* Close the file. */
  213.  
  214.     if (IritPrsrParseError(&ErrorMsg)) {
  215.         fprintf(stderr, "Parse error in \"%s\":\n%s\n", *DataFileNames, ErrorMsg);
  216.         MyExit(1);
  217.     }
  218.  
  219.     DataFileNames++;              /* Skip to next file name. */
  220.     }
  221.  
  222.     if (PObjHead == NULL) {
  223.     fprintf(stderr, "No data found.\n");
  224.     MyExit(1);
  225.     }
  226.  
  227.     return PObjHead;
  228. }
  229.  
  230. /*****************************************************************************
  231. * Routine to convert all surfaces/curves into polylines as follows:         *
  232. * Curves are converted to single polyline with SamplesPerCurve samples.         *
  233. * Surface are converted into GlblNumOfIsolines curves in each axes, each     *
  234. * handled as Curves above. The curves and surfaces are then deleted.         *
  235. *****************************************************************************/
  236. IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs,
  237.                     IPObjectStruct *SrfObjs)
  238. {
  239.     int LocalFourPerFlat;
  240.     float RelativeFineNess;
  241.     CagdCrvStruct *Crvs;
  242.     CagdSrfStruct *Srf, *Srfs;
  243.     IPObjectStruct *PObj, *PObjNext;
  244.     IPPolygonStruct *PPolygon, *PPolygonTemp;
  245.  
  246.     if (CrvObjs == NULL && SrfObjs == NULL) return NULL;
  247.  
  248.     /* Make sure requested format is something reasonable. */
  249.     if (GlblFineNess < 2) {
  250.     GlblFineNess = 2;
  251.     fprintf(stderr, "FineNess is less than 2, 2 picked instead.\n");
  252.     }
  253.  
  254.     if (CrvObjs) {
  255.     /* Curves are not rendered at this time and they are ignored. */
  256.     for (PObj = CrvObjs; PObj != NULL;) {
  257.         Crvs = PObj -> U.PCrvs;
  258.         CagdCrvFreeList(Crvs);
  259.         PObjNext = PObj -> Pnext;
  260.         free((VoidPtr) PObj);
  261.         PObj = PObjNext;
  262.     }
  263.     CrvObjs = NULL;
  264.     }
  265.  
  266.     if (SrfObjs) {
  267.     for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
  268.         char *p;
  269.  
  270.         Srfs = PObj -> U.PSrfs;
  271.         PObj -> U.PPolygon = NULL;
  272.  
  273.         RelativeFineNess = 1.0;
  274.         LocalFourPerFlat = FourPerFlat;
  275.  
  276.         if (IritPrsrGetStrAttrib(PObj, "twoperflat"))
  277.         LocalFourPerFlat = FALSE;
  278.         if (IritPrsrGetStrAttrib(PObj, "fourperflat"))
  279.         LocalFourPerFlat = TRUE;
  280.  
  281.         if ((p = IritPrsrGetStrAttrib(PObj, "resolution")) != NULL &&
  282.         sscanf(p, "%f", &RelativeFineNess) != 1)
  283.         RelativeFineNess = 1.0;
  284.  
  285.         for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
  286.         PPolygon = PPolygonTemp =
  287.             Surface2Polygons(Srf, LocalFourPerFlat,
  288.                      (int) (RelativeFineNess * GlblFineNess));
  289.         while (PPolygonTemp -> Pnext)
  290.             PPolygonTemp = PPolygonTemp -> Pnext;
  291.         PPolygonTemp -> Pnext = PObj -> U.PPolygon;
  292.         PObj -> U.PPolygon = PPolygon;
  293.         }
  294.         CagdSrfFreeList(Srfs);
  295.     }
  296.     }
  297.  
  298.     return SrfObjs;
  299. }
  300.  
  301. /*****************************************************************************
  302. * Routine to convert a single surface into a polylines with SamplesPerCurve  *
  303. * samples, NumOfIsolines isolines into a polyline object list.             *
  304. *****************************************************************************/
  305. static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf, int FourPerFlat,
  306.                      int FineNess)
  307. {
  308.     int i, j;
  309.     IPVertexStruct *V, *VHead,
  310.     *VTail = NULL;
  311.     IPPolygonStruct *P,
  312.     *PHead = NULL;
  313.     CagdPolygonStruct *CagdPolygon,
  314.     *CagdPolygonHead = CagdSrf2Polygons(Srf, FineNess, TRUE, FourPerFlat);
  315.  
  316.     for (CagdPolygon = CagdPolygonHead, VHead = NULL;
  317.      CagdPolygon != NULL;
  318.      CagdPolygon = CagdPolygon -> Pnext) {
  319.     /* All polygons are triangles! */
  320.  
  321.     for (i = 0, VHead = NULL; i < 3; i++) {         /* Convert to vertices. */
  322.         V = IritPrsrNewVertexStruct();
  323.         IP_SET_VRTX_NORMAL(V);             /* This vertex has normal. */
  324.  
  325.         for (j = 0; j < 3; j++)                /* Convert to our format. */
  326.            V -> Coord[j] = CagdPolygon -> Polygon[i].Pt[j];
  327.         for (j = 0; j < 3; j++)
  328.            V -> Normal[j] = CagdPolygon -> Normal[i].Vec[j];
  329.  
  330.         if (VHead) {
  331.         VTail -> Pnext = V;
  332.         VTail = V;
  333.         }
  334.         else
  335.         VHead = VTail = V;
  336.     }
  337.  
  338.     P = IritPrsrNewPolygonStruct();
  339.     P -> PVertex = VHead;
  340.     P -> Type = IP_POLYGON;
  341.     P -> Pnext = PHead;
  342.  
  343.     PHead = P;
  344.     }
  345.  
  346.     CagdPolygonFreeList(CagdPolygonHead);
  347.  
  348.     return PHead;
  349. }
  350.  
  351. /*****************************************************************************
  352. * Dumps the data for NFF into stdout.                         *
  353. *****************************************************************************/
  354. static void DumpDataForNFF(IPObjectStruct *PObjects)
  355. {
  356.     static char *Header1[] = {
  357.     "#",
  358.     "# This file was automatically created from IRIT solid modeller data",
  359.     "# using Irit2Nff - IRIT to NFF filter.",
  360.     "#",
  361.     "#            (c) Copyright 1991/92 Gershon Elber, Non commercial use only.",
  362.     "#",
  363.     NULL
  364.     };
  365.     static char *Header2[] = {
  366.     "",
  367.     "v",
  368.     "from   0  0 10",
  369.     "at     0  0  0",
  370.     "up     0  1  0",
  371.     "angle  12",
  372.     "resolution 512 512",
  373.     "",
  374.     "l      1 1 1",
  375.     "",
  376.     NULL
  377.     };
  378.     int i,
  379.     TotalPolys = 0;
  380.     char Line[128];
  381.     IPObjectStruct *PObj,
  382.     *PObjHead = NULL;
  383.     FILE *FGeom, *FNff;
  384.  
  385.     sprintf(Line, "%s.nff", OutFileName);
  386.     if (!GlblDumpOnlyGeometry) {
  387.         if ((FNff = fopen(Line, "w")) == NULL) {
  388.         fprintf(stderr, "Failed to open \"%s\".\n", Line);
  389.         exit(2);
  390.         }
  391.     }
  392.     else
  393.         FNff = NULL;
  394.  
  395.     if (GlblCPPSupport) {   /* Separated files for geometry/surface quality. */
  396.     sprintf(Line, "%s.geom", OutFileName);
  397.     if ((FGeom = fopen(Line, "w")) == NULL) {
  398.         fprintf(stderr, "Failed to open \"%s\".\n", Line);
  399.         exit(2);
  400.     }
  401.     }
  402.     else
  403.         FGeom = NULL;
  404.  
  405.     if (FNff != NULL) {
  406.         if (GlblCPPSupport)
  407.             fprintf(FNff, "/*\n");
  408.         for (i = 0; Header1[i] != NULL; i++)
  409.         fprintf(FNff, "%s\n", Header1[i]);
  410.         if (GlblCPPSupport)
  411.             fprintf(FNff, "*/\n");
  412.         fprintf(FNff, "\n");
  413.  
  414.         for (i = 0; Header2[i] != NULL; i++)
  415.         fprintf(FNff, "%s\n", Header2[i]);
  416.     }
  417.     
  418.     if (GlblCPPSupport) {
  419.         fprintf(FGeom, "/*\n");
  420.     for (i = 0; Header1[i] != NULL; i++)
  421.         fprintf(FGeom, "%s\n", Header1[i]);
  422.         fprintf(FGeom, "*/\n\n");
  423.     }
  424.  
  425.     /* Reverse object list since it was loaded in reverse by iritprsr module.*/
  426.     while (PObjects != NULL) {
  427.     PObj = PObjects;
  428.     PObjects = PObjects -> Pnext;
  429.     PObj -> Pnext = PObjHead;
  430.     PObjHead = PObj;
  431.     }
  432.     PObjects = PObjHead;
  433.  
  434.     while (PObjects) {
  435.     TotalPolys += DumpOneObject(FNff, FGeom, PObjects);
  436.     PObjects = PObjects -> Pnext;
  437.     }
  438.  
  439.     if (GlblCPPSupport && FNff != NULL)
  440.     fprintf(FNff, "#include \"%s\"\n", Line);
  441.  
  442.     if (FNff != NULL) fclose(FNff);
  443.     if (FGeom != NULL) fclose(FGeom);
  444.  
  445.     fprintf(stderr, "\nTotal number of polygons - %d\n", TotalPolys);
  446. }
  447.  
  448. /*****************************************************************************
  449. * Routine to dump one object PObject.                         *
  450. *****************************************************************************/
  451. static int DumpOneObject(FILE *FNff, FILE *FGeom, IPObjectStruct *PObject)
  452. {
  453.     static int
  454.     ObjectSeqNum = 1;
  455.     int i, j,
  456.         PolyCount = 0,
  457.     HasColor = FALSE;
  458.     char *p, Name[LINE_LEN], SrfPropString[LINE_LEN_LONG];
  459.     RealType RGBColor[3];
  460.     IPPolygonStruct
  461.     *PList = PObject -> U.PPolygon;
  462.  
  463.     if (strlen(PObject -> Name) == 0)
  464.     sprintf(Name, "ObjSeq%d", ObjectSeqNum);
  465.     else
  466.     strcpy(Name, PObject -> Name);
  467.  
  468.     SrfPropString[0] = 0;
  469.     if ((p = IritPrsrGetStrAttrib(PObject, "kd")) != NULL)
  470.     STRCAT2(SrfPropString, " ", p);
  471.     else
  472.     strcat(SrfPropString, DEFAULT_KD);
  473.     if ((p = IritPrsrGetStrAttrib(PObject, "ks")) != NULL)
  474.     STRCAT2(SrfPropString, " ", p);
  475.     else
  476.     strcat(SrfPropString, DEFAULT_KS);
  477.     if ((p = IritPrsrGetStrAttrib(PObject, "shine")) != NULL)
  478.     STRCAT2(SrfPropString, " ", p);
  479.     else
  480.     strcat(SrfPropString, DEFAULT_SHINE);
  481.     if ((p = IritPrsrGetStrAttrib(PObject, "trans")) != NULL)
  482.     STRCAT2(SrfPropString, " ", p);
  483.     else
  484.     strcat(SrfPropString, DEFAULT_TRANS);
  485.     if ((p = IritPrsrGetStrAttrib(PObject, "index")) != NULL)
  486.     STRCAT2(SrfPropString, " ", p);
  487.     else
  488.     strcat(SrfPropString, DEFAULT_INDEX);
  489.  
  490.     if ((p = IritPrsrGetStrAttrib(PObject, "rgb")) != NULL)
  491.     {
  492. #    ifdef __MSDOS__
  493.         HasColor = sscanf(p, "%f,%f,%f",
  494. #    else
  495.         HasColor = sscanf(p, "%lf,%lf,%lf",
  496. #    endif /* __MSDOS__ */
  497.                   &RGBColor[0], &RGBColor[1], &RGBColor[2]) == 3;
  498.     }
  499.     else if (IP_HAS_OBJ_RGB(PObject)) {
  500.     HasColor = TRUE;
  501.     for (i = 0; i < 3; i++) RGBColor[i] = PObject -> RGB[i];
  502.     }
  503.     else if (IP_HAS_OBJ_COLOR(PObject)) {
  504.     for (i = 0; TransColorTable[i][0] >= 0; i++) {
  505.         if (TransColorTable[i][0] == PObject -> Color) {
  506.         HasColor = TRUE;
  507.         for (j = 0; j < 3; j++) RGBColor[j] = TransColorTable[i][j+1];
  508.         break;
  509.         }
  510.     }
  511.     }
  512.  
  513.     if (FNff != NULL)
  514.         fprintf(FNff, GlblCPPSupport ? "/*\n#\n# %s\n#\n*/\n" : "#\n# %s\n#\n",
  515.             Name);
  516.     if (GlblCPPSupport) {
  517.     if (FNff != NULL) fprintf(FNff, "#define %s_SRF_PROP ", Name);
  518.     fprintf(FGeom, "/*\n#\n# %s\n#\n*/\n", Name);
  519.     fprintf(FGeom, "f %s_SRF_PROP\n", Name);
  520.     }
  521.     else {
  522.     if (FNff != NULL) fprintf(FNff, "f ");
  523.     }
  524.     if (HasColor) {
  525.     for (i = 0; i < 3; i++) RGBColor[i] /= 255.0;
  526.     if (FNff != NULL) fprintf(FNff, "%7.4lf %7.4lf %7.4lf",
  527.                   RGBColor[0], RGBColor[1], RGBColor[2]);
  528.     }
  529.     else {
  530.     if (FNff != NULL) fprintf(FNff, "%s", DEFAULT_COLOR);
  531.     }
  532.     if (FNff != NULL) fprintf(FNff, " %s\n\n", SrfPropString);
  533.  
  534.     while (PList) {
  535.     PolyCount += DumpOnePolygon(GlblCPPSupport ? FGeom : FNff, PList);
  536.     PList =    PList -> Pnext;
  537.     }
  538.  
  539.     fprintf(stderr, "Processing \"%s\" - %d triangles.\n", Name, PolyCount);
  540.  
  541.     if (FNff != NULL) fprintf(FNff, "\n\n");
  542.     if (GlblCPPSupport)
  543.     fprintf(FGeom, "\n\n");
  544.  
  545.     ObjectSeqNum++;
  546.  
  547.     return PolyCount;
  548. }
  549.  
  550.  
  551. /*****************************************************************************
  552. * Routine to dump one polygon, using global Matrix transform CrntViewMat.    *
  553. *****************************************************************************/
  554. static int DumpOnePolygon(FILE *Fl, IPPolygonStruct *PPolygon)
  555. {
  556.     int i,
  557.     TriCount = 0;
  558.     RealType *MappedNormal[3], *MappedPoint[3], Normal[3], Vec1[3], Vec2[3];
  559.     IPVertexStruct *VFirst, *V1, *V2,
  560.     *VList = PPolygon -> PVertex;
  561.  
  562.     if (Fl == NULL || VList == NULL) return 0;
  563.  
  564.     if (!IsConvexPolygon(PPolygon)) {
  565.     static int Printed = FALSE;
  566.  
  567.     if (!Printed) {
  568.         fprintf(stderr,
  569.             "Non convex polygon(s) may be in data (see CONVEX in IRIT).\n");
  570.         Printed = TRUE;
  571.     }
  572.     }
  573.  
  574.     switch (PPolygon -> Type) {
  575.     case IP_POLYGON:
  576.         VFirst = VList;
  577.         V1 = VFirst -> Pnext;
  578.         V2 = V1 -> Pnext;
  579.  
  580.         while (V2 != NULL) {
  581.         MappedPoint[0] = MapPoint(VFirst -> Coord);
  582.         MappedPoint[1] = MapPoint(V1 -> Coord);
  583.         MappedPoint[2] = MapPoint(V2 -> Coord);
  584.  
  585.         /* Test for two type of degeneracies. Make sure that no two  */
  586.         /* points in the triangle are the same and that they are     */
  587.         /* not colinear.                         */
  588.         if (!PT_EQ(MappedPoint[0], MappedPoint[1]) &&
  589.             !PT_EQ(MappedPoint[0], MappedPoint[2]) &&
  590.             !PT_EQ(MappedPoint[1], MappedPoint[2])) {
  591.  
  592.             PT_SUB(Vec1, MappedPoint[0], MappedPoint[1]);
  593.             PT_SUB(Vec2, MappedPoint[1], MappedPoint[2]);
  594.             PT_NORMALIZE(Vec1);
  595.             PT_NORMALIZE(Vec2);
  596.             CROSS_PROD(Normal, Vec1, Vec2);
  597.  
  598.             if (PT_LENGTH(Normal) > SIZE_EPSILON) {
  599.             PT_NORMALIZE(Normal);
  600.  
  601.             MappedNormal[0] =
  602.                 MapVector(VFirst -> Coord, VFirst -> Normal);
  603.             MappedNormal[1] =
  604.                 MapVector(V1 -> Coord, V1 -> Normal);
  605.             MappedNormal[2] =
  606.                 MapVector(V2 -> Coord, V2 -> Normal);
  607.  
  608.             if (DOT_PROD(Normal, MappedNormal[0]) < -SIZE_EPSILON ||
  609.                 DOT_PROD(Normal, MappedNormal[1]) < -SIZE_EPSILON ||
  610.                 DOT_PROD(Normal, MappedNormal[2]) < -SIZE_EPSILON) {
  611.                 SWAP(RealType *, MappedPoint[1], MappedPoint[2]);
  612.                 SWAP(RealType *, MappedNormal[1], MappedNormal[2]);
  613.                 PT_SCALE(Normal, -1.0);
  614.                 }
  615.  
  616.                 /* Make sure all normals are set properly: */
  617.                 if (DOT_PROD(MappedNormal[0], MappedNormal[0]) < SIZE_EPSILON)
  618.                 PT_COPY(MappedNormal[0], Normal);
  619.                 if (DOT_PROD(MappedNormal[1], MappedNormal[1]) < SIZE_EPSILON)
  620.                 PT_COPY(MappedNormal[1], Normal);
  621.                 if (DOT_PROD(MappedNormal[2], MappedNormal[2]) < SIZE_EPSILON)
  622.                 PT_COPY(MappedNormal[2], Normal);
  623.  
  624.                 TriCount++;
  625.  
  626.                 fprintf(Fl, "pp 3\n");
  627.                 for (i = 0; i < 3; i++)
  628.                 fprintf(Fl,
  629.                 "  %10.7lf %10.7lf %10.7lf  %9.6lf %9.6lf %9.6lf\n",
  630.                     MappedPoint[i][0],
  631.                     MappedPoint[i][1],
  632.                     MappedPoint[i][2],
  633.                     MappedNormal[i][0],
  634.                     MappedNormal[i][1],
  635.                     MappedNormal[i][2]);
  636.             }
  637.         }
  638.  
  639.         V1 = V2;
  640.         V2 = V2 -> Pnext;
  641.         }
  642.         break;
  643.     }
  644.  
  645.     return TriCount;
  646. }
  647.  
  648. /*****************************************************************************
  649. *   Routine to test if the given polygon is convex or not.             *
  650. * Algorithm: The polygon is convex iff the normals generated from cross      *
  651. * products of two consecutive edges points to the same direction. The same   *
  652. * direction is tested by a positive dot product.                 *
  653. *****************************************************************************/
  654. static int IsConvexPolygon(IPPolygonStruct *Pl)
  655. {
  656.     RealType Size, V1[3], V2[3], LastNormal[3], Normal[3];
  657.     IPVertexStruct *VNext, *VNextNext,
  658.     *V = Pl -> PVertex;
  659.  
  660.     LastNormal[0] = LastNormal[1] = LastNormal[2] = 0.0;
  661.  
  662.     do {
  663.     if ((VNext = V -> Pnext) == NULL)
  664.         VNext = Pl -> PVertex;
  665.     if ((VNextNext = VNext -> Pnext) == NULL)
  666.         VNextNext = Pl -> PVertex;
  667.  
  668.     PT_SUB(V1, VNext -> Coord, V -> Coord);
  669.     if ((Size = PT_LENGTH(V1)) > EPSILON) {
  670.         Size = 1.0 / Size;
  671.         PT_SCALE(V1, Size);
  672.     }
  673.     PT_SUB(V2, VNextNext -> Coord, VNext -> Coord);
  674.     if ((Size = PT_LENGTH(V2)) > EPSILON) {
  675.         Size = 1.0 / Size;
  676.         PT_SCALE(V2, Size);
  677.     }
  678.     CROSS_PROD(Normal, V1, V2);
  679.  
  680.     if (V != Pl -> PVertex) {
  681.         if (PT_LENGTH(Normal) > CONVEX_EPSILON &&
  682.         DOT_PROD(Normal, LastNormal) < -CONVEX_EPSILON)
  683.         return FALSE;
  684.     }
  685.  
  686.     PT_COPY(LastNormal, Normal);
  687.  
  688.     V = VNext;
  689.     }
  690.     while (V != Pl -> PVertex && V != NULL);
  691.  
  692.     return TRUE;
  693. }
  694.  
  695. /*****************************************************************************
  696. * Maps the given E3 point using the CrntViewMat.                 *
  697. *****************************************************************************/
  698. static RealType *MapPoint(RealType *Pt)
  699. {
  700.     static int Count = 0;
  701.     static RealType MappedPts[3][3];
  702.     RealType *MappedPt = MappedPts[Count++];
  703.  
  704.     if (Count >= 3) Count = 0;
  705.  
  706.     MultVecby4by4(MappedPt, Pt, CrntViewMat);
  707.  
  708.     return MappedPt;
  709. }
  710.  
  711. /*****************************************************************************
  712. * Maps the given E3 vector using the CrntViewMat.                 *
  713. * This routine will return a zero vector if normal is not computable.         *
  714. *****************************************************************************/
  715. static RealType *MapVector(RealType *Pt, RealType *Vec)
  716. {
  717.     static int
  718.     Count = 0,
  719.     WasWarning = 0;
  720.     static RealType MappedVecs[3][3];
  721.     RealType MappedPt[3], Pt2[3], MappedPt2[3],
  722.     *MappedVec = MappedVecs[Count++];
  723.  
  724.     if (Count >= 3) Count = 0;
  725.  
  726.     if (DOT_PROD(Vec, Vec) < SIZE_EPSILON) {
  727.     MappedVec[0] = MappedVec[1] = MappedVec[2] = 0.0;
  728.     if (!WasWarning) {
  729.         WasWarning = 1;
  730.         fprintf(stderr, "Non computable normals detected. Approximated from geometry.\n");
  731.     }
  732.     }
  733.     else {
  734.         MultVecby4by4(MappedPt, Pt, CrntViewMat);
  735.  
  736.         PT_ADD(Pt2, Pt, Vec);
  737.         MultVecby4by4(MappedPt2, Pt2, CrntViewMat);
  738.  
  739.         PT_SUB(MappedVec, MappedPt2, MappedPt);
  740.         PT_NORMALIZE(MappedVec);
  741.     }
  742.  
  743.     return MappedVec;
  744. }
  745.  
  746. /*****************************************************************************
  747. * Trap Cagd_lib errors right here.                         *
  748. *****************************************************************************/
  749. void CagdFatalError(CagdFatalErrorType ErrID)
  750. {
  751.     char
  752.     *ErrorMsg = CagdDescribeError(ErrID);
  753.  
  754.     fprintf(stderr, "CAGD_LIB: %s", ErrorMsg);
  755.  
  756.     exit(-1);
  757. }
  758.  
  759. /*****************************************************************************
  760. * MyExit routine. Note it might call to CloseGraph without calling         *
  761. * InitGraph(), or call MouseClose() without MouseInit() etc. and it is the   *
  762. * responsibility of the individual modules to do nothing in these cases.     *
  763. *****************************************************************************/
  764. static void MyExit(int ExitCode)
  765. {
  766. #ifdef __MSDOS__
  767.     fprintf(stderr,
  768.         "\nIrit2Nff: Core left %ldk.\n", coreleft() / 1024);
  769. #endif /* __MSDOS__ */
  770.  
  771.     exit(ExitCode);
  772. }
  773.